package main.core.xml;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import main.core.Item;
import main.core.Settings;
import main.core.utils.Useful;

public class XMLItemsSaver {
	
	public static void saveFile(String fileName, ArrayList<Item> items, int type)
	{
		try {
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder;
			docBuilder = docFactory.newDocumentBuilder();
	 
			Document doc = docBuilder.newDocument();
			Element bpe_el = doc.createElement(XMLItems.BPE);
			doc.appendChild(bpe_el);
			
			if(type == XMLItems.SETTINGS_TYPE) //Settings
			{
				Element set_el = doc.createElement(XMLItems.SETTINGS);
				writeSettings(doc, set_el);
				bpe_el.appendChild(set_el);
			} else if(type == XMLItems.ITEMS_TYPE) //Items
			{
				Element its_el = doc.createElement(XMLItems.ITEMS);
				writeItems(doc, its_el, items);
				bpe_el.appendChild(its_el);
			}
			TransformerFactory transformerFactory = TransformerFactory.newInstance();
			Transformer transformer = transformerFactory.newTransformer();
			DOMSource source = new DOMSource(doc);
			StreamResult result = new StreamResult(new File(fileName));
	 
			// Output to console for testing
			//StreamResult result = new StreamResult(System.out);
	 
			transformer.transform(source, result);
	 
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerConfigurationException e) {
			e.printStackTrace();
		} catch (TransformerException e) {
			e.printStackTrace();
		}
	}
	
	private static void writeItems(Document doc, Element its_el, ArrayList<Item> items)
	{
		Iterator<Item> iterator = items.iterator();
		while(iterator.hasNext())
		{
			Item cursor = iterator.next();
			if(cursor != null)
			{
				Element it_el = doc.createElement(XMLItems.ITEM);
				writeItem(doc, it_el, cursor);
				its_el.appendChild(it_el);
			}
		}
	}
	
	private static void writeItem(Document doc, Element it_el, Item item)
	{
		Class<?> item_class = Item.class;
		Field[] fields = item_class.getDeclaredFields();
		for(int i = 0; i < fields.length; ++i)
		{
			String property = fields[i].getName();
			Element tag = doc.createElement(Useful.getGetter(property));
			tag.setTextContent(getItemPropertyValue(property, item));
			it_el.appendChild(tag);
		}
	}
	
	private static String getItemPropertyValue(String property, Item item)
	{
		String value = "";
		try {
			Class<?> cls = Item.class;
			Class<?> partypes[] = new Class[0];
			Method meth = cls.getMethod(Useful.getGetter(property), partypes);
			Object arglist[] = new Object[0];
			value = "" + meth.invoke(item, arglist);
		}
		catch (Throwable e) {
			System.err.println(e);
		}
		return value;
	}

	private static void writeSettings(Document doc, Element set_el)
	{
		Class<?> set_class = Settings.class;
		Field[] fields = set_class.getDeclaredFields();
		for(int i = 0; i < fields.length; ++i)
		{
			String property = fields[i].getName();
			if(!property.equals("m_instance"))
			{
				Element tag = doc.createElement(Useful.getGetter(property));
				tag.setTextContent(getSettingsPropertyValue(property));
				set_el.appendChild(tag);
			}
		}
	}
	
	private static String getSettingsPropertyValue(String property)
	{
		String value = "";
		try {
			Class<?> cls = Settings.class;
			Class<?> partypes[] = new Class[0];
			Method meth = cls.getMethod(Useful.getGetter(property), partypes);
			Settings set = Settings.getInstance();
			Object arglist[] = new Object[0];
			value = "" + meth.invoke(set, arglist);
		}
		catch (Throwable e) {
			System.err.println(e);
		}
		return value;
	}
}
